package com.alibaba.yinan.graph;

import lombok.Getter;
import org.jgrapht.Graph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.AsSubgraph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @ClassName GraphService
 * @Description 有向图 + 双向边 + 路径搜索（占用/组互斥由 NodeOccupancyManager 处理）
 */
@Service
public class GraphService {

    @Autowired
    private NodeOccupancyManager occupancyManager;

    @Getter
    private final Graph<String, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);

    private final Set<String> bidirectionalEdges = ConcurrentHashMap.newKeySet();

    /* ------------------- 节点和边 ------------------- */

    public void addNode(String node) {
        graph.addVertex(node);
    }

    public void addEdge(String from, String to) {
        graph.addEdge(from, to);
    }

    public void addBidirectionalEdge(String a, String b) {
        graph.addEdge(a, b);
        graph.addEdge(b, a);
        bidirectionalEdges.add(edgeKey(a, b));
        bidirectionalEdges.add(edgeKey(b, a));
    }

    public boolean isBidirectionalEdge(String from, String to) {
        return bidirectionalEdges.contains(edgeKey(from, to));
    }

    private String edgeKey(String from, String to) {
        return from + "->" + to;
    }

    /* ------------------- 路径搜索 ------------------- */

    /**
     * 查找最短路径，排除占用节点（组内互斥已经由 occupancyManager 管理）
     */
    public List<String> findShortestPath(String start, String end, Set<String> requestOccupied) {
        Set<String> occupied = occupancyManager.getAllOccupiedNodes();
        if (requestOccupied != null) {
            occupied.addAll(requestOccupied);
        }

        occupied.remove(start); // 起点始终可用

        Set<String> availableVertices = graph.vertexSet().stream()
                .filter(v -> !occupied.contains(v))
                .collect(Collectors.toSet());

        if (!availableVertices.contains(start) || !availableVertices.contains(end)) {
            return Collections.emptyList();
        }

        Graph<String, DefaultEdge> subGraph = new AsSubgraph<>(graph, availableVertices);
        DijkstraShortestPath<String, DefaultEdge> dijkstra = new DijkstraShortestPath<>(subGraph);
        GraphPath<String, DefaultEdge> path = dijkstra.getPath(start, end);

        return path != null ? path.getVertexList() : Collections.emptyList();
    }

    /**
     * 路径占用/释放辅助方法
     */
    public boolean occupyPath(String machineId, List<String> path) {
        return occupancyManager.occupyNodes(machineId, path);
    }

    public void releasePath(String machineId, List<String> path) {
        occupancyManager.releaseNodes(machineId, path);
    }

    /* ------------------- 查询辅助 ------------------- */
    public Set<String> getAllNodes() {
        return graph.vertexSet();
    }

    public Set<DefaultEdge> getAllEdges() {
        return graph.edgeSet();
    }
}
